home *** CD-ROM | disk | FTP | other *** search
/ IO CD February 1999 / IO_LUTY_99.ISO / DODATKI / Brood War / GREETBOT.ZIP / BNBOT.CPP next >
C/C++ Source or Header  |  1998-03-31  |  13KB  |  533 lines

  1. //
  2. // BNBOT.CPP
  3. //
  4. // Implementation of a virtual base class for Battle.net bots.
  5. //
  6. // by Scott Coleman 3/31/98
  7. //
  8. //
  9.  
  10.  
  11. #include "pch.h"
  12. #pragma hdrstop
  13.  
  14.  
  15. #define BUFSIZE         2048
  16.  
  17.  
  18. // event IDs
  19. #define EID_SHOWUSER            1001
  20. #define EID_JOIN                1002
  21. #define EID_LEAVE               1003
  22. #define EID_WHISPER             1004
  23. #define EID_TALK                1005
  24. #define EID_BROADCAST           1006
  25. #define EID_CHANNEL             1007
  26. #define EID_USERFLAGS           1009
  27. #define EID_WHISPERSENT         1010
  28. #define EID_CHANNELFULL         1013
  29. #define EID_CHANNELDOESNOTEXIST 1014
  30. #define EID_CHANNELRESTRICTED   1015
  31. #define EID_INFO                1018
  32. #define EID_ERROR               1019
  33. #define EID_EMOTE               1023
  34. #define EID_UNIQUENAME          2010
  35.  
  36.  
  37.  
  38.  
  39. //============================================================================
  40. BnBot::BnBot() {
  41.  
  42.   log = 0;
  43.   s = INVALID_SOCKET;
  44.   nServerPort = 6112;
  45.   szLoginName[0] = '\0';
  46.   szUniqueName[0] = '\0';
  47.   szPassword[0] = '\0';
  48.   szServerAddr[0] = '\0';
  49.   szHomeChannel[0] = '\0';
  50.   szCurrentChannel[0] = '\0';
  51. }
  52.  
  53.  
  54. //============================================================================
  55. BnBot::~BnBot() {
  56.  
  57.   LogClose();
  58. }
  59.  
  60.  
  61. //============================================================================
  62. void BnBot::SetLogonInfo(char *szUserName,
  63.                          char *szUserPass,
  64.                          char *szServer,
  65.                          short nPort) {
  66.  
  67.   strcpy(szLoginName, szUserName);
  68.   strcpy(szUniqueName, szUserName);
  69.   strcpy(szPassword, szUserPass);
  70.   strcpy(szServerAddr, szServer);
  71.   nServerPort = nPort;
  72. }
  73.  
  74.  
  75. //============================================================================
  76. void BnBot::SetHomeChannel(char *szChannelName) {
  77.  
  78.   strcpy(szHomeChannel, szChannelName);
  79. }
  80.  
  81.  
  82. //============================================================================
  83. int BnBot::Connect() {
  84.   struct sockaddr_in name;
  85.   struct hostent *hp;
  86.  
  87.   memset(&name, '\0', sizeof(name));
  88.   name.sin_family = AF_INET;
  89.   name.sin_port = htons(nServerPort);
  90.  
  91.   // if this is a hostname and not an IP address, resolve it
  92.   char *p = szServerAddr;
  93.   while (*p && (isdigit(*p) || (*p == '.'))) {
  94.     p++;
  95.   }
  96.  
  97.   // non-digit found - assume hostname
  98.   if (*p) {
  99.     hp = gethostbyname(szServerAddr);
  100.     if (hp == 0)
  101.       return 0;         // can't resolve hostname
  102.     memcpy(&name.sin_addr, hp->h_addr, hp->h_length);
  103.   }
  104.   else {
  105.     name.sin_addr.s_addr = inet_addr(szServerAddr);
  106.   }
  107.  
  108.   s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  109.   if (s == INVALID_SOCKET) {
  110.     return 0;
  111.   }
  112.  
  113.   if (connect(s, (struct sockaddr *)&name, sizeof(name))) {
  114.     return 0;
  115.   }
  116.  
  117.   return 1;
  118. }
  119.  
  120.  
  121. //============================================================================
  122. int BnBot::Logon() {
  123.  
  124.   // send ^C, ^D, username, and password
  125.   // ^C gets the server's attention for logon; ^D turns off ECHO
  126.   Send("%c%c%s\r\n%s\r\n", 0x03, 0x04, szLoginName, szPassword);
  127.  
  128.   return 1;
  129. }
  130.  
  131.  
  132. //============================================================================
  133. void BnBot::Disconnect() {
  134.  
  135.   if (s == INVALID_SOCKET)
  136.     return;
  137.  
  138.   closesocket(s);
  139.   s = INVALID_SOCKET;
  140. }
  141.  
  142.  
  143. //============================================================================
  144. int BnBot::Reconnect() {
  145.  
  146.   LogWrite("Attempting to connect...");
  147.   for (int tries=0; tries < 10; ++tries) {
  148.     if (!Connect()) {
  149.       LogWrite("Connect() failed.");
  150.       Sleep(5000);
  151.       continue;
  152.     }
  153.     if (!Logon()) {
  154.       LogWrite("Logon() failed.");
  155.       continue;
  156.     }
  157.     Sleep(1000);
  158.     Send("/join %s\r\n", szHomeChannel);
  159.     return 1;
  160.   }
  161.   LogWrite("Unable to log on after %d tries - giving up.", tries);
  162.   return 0;
  163. }
  164.  
  165.  
  166. //============================================================================
  167. int __cdecl BnBot::Send(char *lpszFmt, ...) {
  168.   char szOutStr[MAXTEXTLENGTH];
  169.   va_list argptr;
  170.  
  171.   va_start(argptr, lpszFmt);
  172.   vsprintf(szOutStr, lpszFmt, argptr);
  173.   va_end(argptr);
  174.  
  175.   if (send(s, szOutStr, strlen(szOutStr), 0) < 0)
  176.     return 0;
  177.  
  178.   return 1;
  179. }
  180.  
  181.  
  182. //============================================================================
  183. int BnBot::ParseEvent(char *pszEvent,
  184.                       int *pnEventId,
  185.                       char *pszSpeaker,
  186.                       u_long *puFlags,
  187.                       char *pszEventText) {
  188.  
  189.   if (!pszEvent || !pnEventId || !pszSpeaker || !puFlags || !pszEventText)
  190.     return 1;
  191.  
  192.   *pszSpeaker = '\0';
  193.   *pszEventText = '\0';
  194.   *puFlags = 0;
  195.  
  196.   *pnEventId = atoi(pszEvent);
  197.  
  198.   // some event messages have no speaker or flag fields
  199.   if ((*pnEventId != EID_INFO) && (*pnEventId != EID_CHANNELFULL) &&
  200.       (*pnEventId != EID_CHANNEL) &&
  201.       (*pnEventId != EID_CHANNELDOESNOTEXIST) &&
  202.       (*pnEventId != EID_CHANNELRESTRICTED) && (*pnEventId != EID_ERROR)) {
  203.  
  204.     char szJunk[MAXSTRINGLENGTH];
  205.     sscanf(pszEvent, "%d %s %s %x", pnEventId, szJunk, pszSpeaker, puFlags);
  206.   }
  207.  
  208.   // the event text is enclosed in quotes
  209.   char *p = strchr(pszEvent, '"');
  210.   if (p) {
  211.     strncpy(pszEventText, p+1, MAXTEXTLENGTH);
  212.     pszEventText[MAXTEXTLENGTH-1] = '\0';
  213.  
  214.     // nix the trailing quote
  215.     p = strrchr(pszEventText, '"');
  216.     if (p)
  217.       *p = '\0';
  218.   }
  219.  
  220.   return 1;
  221. }
  222.  
  223.  
  224. //============================================================================
  225. int BnBot::Dispatch(char *szEventMsg) {
  226.   int nEventId;
  227.   u_long uFlags;
  228.   char szSpeaker[MAXSTRINGLENGTH] = "";
  229.   char szEventText[MAXTEXTLENGTH] = "";
  230.  
  231.   if (!ParseEvent(szEventMsg,
  232.                   &nEventId,
  233.                   szSpeaker,
  234.                   &uFlags,
  235.                   szEventText)) {
  236.     return 0;
  237.   }
  238.  
  239.   // dispatch to the appropriate event handler
  240.   switch (nEventId) {
  241.     case EID_SHOWUSER:
  242.       OnShowUser(szSpeaker, uFlags, szEventText);
  243.     break;
  244.  
  245.     case EID_JOIN:
  246.       OnJoin(szSpeaker, uFlags, szEventText);
  247.     break;
  248.  
  249.     case EID_USERFLAGS:
  250.       OnUserFlags(szSpeaker, uFlags, szEventText);
  251.     break;
  252.  
  253.     case EID_LEAVE:
  254.       OnLeave(szSpeaker, uFlags, szEventText);
  255.     break;
  256.  
  257.     case EID_TALK:
  258.       OnTalk(szSpeaker, uFlags, szEventText);
  259.     break;
  260.  
  261.     case EID_BROADCAST:
  262.       OnBroadcast(szSpeaker, uFlags, szEventText);
  263.     break;
  264.  
  265.     case EID_CHANNEL:
  266.       OnChannel(szSpeaker, uFlags, szEventText);
  267.     break;
  268.  
  269.     case EID_WHISPER:
  270.       OnWhisper(szSpeaker, uFlags, szEventText);
  271.     break;
  272.  
  273.     case EID_WHISPERSENT:
  274.       OnWhisperSent(szSpeaker, uFlags, szEventText);
  275.     break;
  276.  
  277.     case EID_EMOTE:
  278.       OnEmote(szSpeaker, uFlags, szEventText);
  279.     break;
  280.  
  281.     case EID_CHANNELFULL:
  282.       OnChannelFull(szSpeaker, uFlags, szEventText);
  283.     break;
  284.  
  285.     case EID_CHANNELDOESNOTEXIST:
  286.       OnChannelDoesNotExist(szSpeaker, uFlags, szEventText);
  287.     break;
  288.  
  289.     case EID_CHANNELRESTRICTED:
  290.       OnChannelRestricted(szSpeaker, uFlags, szEventText);
  291.     break;
  292.  
  293.     case EID_INFO:
  294.       OnInfo(szSpeaker, uFlags, szEventText);
  295.     break;
  296.  
  297.     case EID_ERROR:
  298.       OnError(szSpeaker, uFlags, szEventText);
  299.     break;
  300.  
  301.     case EID_UNIQUENAME:
  302.       OnUniqueName(szSpeaker, uFlags, szEventText);
  303.     break;
  304.  
  305.     default:
  306.       LogWrite("Unhandled event ID %d", nEventId);
  307.       return 0;
  308.     break;
  309.   }
  310.  
  311.   return 1;
  312. }
  313.  
  314.  
  315. //============================================================================
  316. int BnBot::MsgLoop() {
  317.   int nBufLen=0;
  318.   int nBufPos=0;
  319.   char stageBuf[BUFSIZE];
  320.  
  321.   if (s == INVALID_SOCKET)
  322.     return 0;
  323.  
  324.   for (;;) {
  325.     fd_set fds;
  326.     FD_ZERO(&fds);
  327.     FD_SET(s, &fds);
  328.     struct timeval tv;
  329.     tv.tv_sec = 1;
  330.     tv.tv_usec = 0;
  331.  
  332.     int n = select(s+1, &fds, 0, 0, &tv);
  333.     if (n) {
  334.       int nNumToRead = BUFSIZE-nBufLen-nBufPos;
  335.  
  336.       if (nNumToRead == 0) {
  337.         memmove(stageBuf, stageBuf+nBufPos, nBufLen);
  338.         nBufPos = 0;
  339.         nNumToRead = BUFSIZE-nBufLen;
  340.       }
  341.  
  342.       n = recv(s, stageBuf+nBufPos+nBufLen, nNumToRead, 0);
  343.       if (n <= 0) {
  344.         LogWrite("recv() returned %d, error code %u", n, GetLastError());
  345.         return 0;
  346.       }
  347.  
  348.       nBufLen += n;
  349.  
  350.       // dispatch all complete messages in the staging buffer
  351.       while (nBufLen > 0) {
  352.         char *m = stageBuf+nBufPos;
  353.         int nMsgLen=0;
  354.         while (nMsgLen < nBufLen) {
  355.           if (m[nMsgLen] == '\n')
  356.             break;
  357.           nMsgLen++;
  358.         }
  359.  
  360.         nMsgLen++;
  361.         if (nMsgLen > nBufLen)
  362.           break;
  363.  
  364.         m[nMsgLen-1] = '\0';
  365.  
  366.         if (isdigit(*m))
  367.           Dispatch(m);
  368.  
  369.         nBufLen -= nMsgLen;
  370.         nBufPos += nMsgLen;
  371.       }
  372.  
  373.       if (!nBufLen)
  374.         nBufPos = 0;
  375.     }
  376.     IdleHook();
  377.   }
  378.   return 1;
  379. }
  380.  
  381.  
  382. //=============================================================================
  383. int BnBot::LogOpen(char *lpszFileName) {
  384.  
  385.   if (log) {
  386.     return 0;
  387.   }
  388.  
  389.   log = fopen(lpszFileName, "ab");
  390.   if (!log)
  391.     return 0;
  392.  
  393.   return 1;
  394. }
  395.  
  396.  
  397. //=============================================================================
  398. int __cdecl BnBot::LogWrite(char *lpszFmt, ...) {
  399.   va_list argptr;
  400.   char szOutStr[1024];
  401.  
  402.   if (!log)
  403.     return 0;
  404.  
  405.   va_start(argptr, lpszFmt);
  406.   vsprintf(szOutStr, lpszFmt, argptr);
  407.   va_end(argptr);
  408.  
  409.   fprintf(log, "%s\r\n", szOutStr);
  410.   return 1;
  411. }
  412.  
  413.  
  414. //=============================================================================
  415. void BnBot::LogClose() {
  416.  
  417.   if (log)
  418.     fclose(log);
  419.   log = 0;
  420. }
  421.  
  422.  
  423. /*****************************************************************************
  424. *
  425. * Virtual Event Handlers
  426. *
  427. ******/
  428.  
  429.  
  430. //============================================================================
  431. inline int BnBot::OnShowUser(char *szSpeaker, u_long uFlags, char *szEventText) {
  432.  
  433.   return 1;
  434. }
  435.  
  436. //============================================================================
  437. inline int BnBot::OnJoin(char *szSpeaker, u_long uFlags, char *szEventText) {
  438.  
  439.   return 1;
  440. }
  441.  
  442. //============================================================================
  443. inline int BnBot::OnUserFlags(char *szSpeaker,
  444.                               u_long uFlags,
  445.                               char *szEventText) {
  446.  
  447.   return 1;
  448. }
  449.  
  450. //============================================================================
  451. inline int BnBot::OnLeave(char *szSpeaker, u_long uFlags, char *szEventText) {
  452.  
  453.   return 1;
  454. }
  455.  
  456. //============================================================================
  457. inline int BnBot::OnTalk(char *szSpeaker, u_long uFlags, char *szEventText) {
  458.  
  459.   return 1;
  460. }
  461.  
  462. //============================================================================
  463. inline int BnBot::OnBroadcast(char *szSpeaker, u_long uFlags, char *szEventText) {
  464.  
  465.   return 1;
  466. }
  467.  
  468. //============================================================================
  469. inline int BnBot::OnChannel(char *szSpeaker, u_long uFlags, char *szEventText) {
  470.  
  471.   strcpy(szCurrentChannel, szEventText);
  472.   return 1;
  473. }
  474.  
  475. //============================================================================
  476. inline int BnBot::OnWhisper(char *szSpeaker, u_long uFlags, char *szEventText) {
  477.  
  478.   return 1;
  479. }
  480.  
  481. //============================================================================
  482. inline int BnBot::OnWhisperSent(char *szSpeaker, u_long uFlags, char *szEventText) {
  483.  
  484.   return 1;
  485. }
  486.  
  487. //============================================================================
  488. inline int BnBot::OnEmote(char *szSpeaker, u_long uFlags, char *szEventText) {
  489.  
  490.   return 1;
  491. }
  492.  
  493. //============================================================================
  494. inline int BnBot::OnChannelFull(char *szSpeaker, u_long uFlags, char *szEventText) {
  495.  
  496.   return 1;
  497. }
  498.  
  499. //============================================================================
  500. inline int BnBot::OnChannelDoesNotExist(char *szSpeaker, u_long uFlags,
  501.                                  char *szEventText) {
  502.  
  503.   return 1;
  504. }
  505.  
  506. //============================================================================
  507. inline int BnBot::OnChannelRestricted(char *szSpeaker, u_long uFlags,
  508.                                char *szEventText) {
  509.  
  510.   return 1;
  511. }
  512.  
  513. //============================================================================
  514. inline int BnBot::OnInfo(char *szSpeaker, u_long uFlags, char *szEventText) {
  515.  
  516.   return 1;
  517. }
  518.  
  519. //============================================================================
  520. inline int BnBot::OnError(char *szSpeaker, u_long uFlags, char *szEventText) {
  521.  
  522.   return 1;
  523. }
  524.  
  525.  
  526. //============================================================================
  527. inline int BnBot::OnUniqueName(char *szSpeaker, u_long uFlags, char *szEventText) {
  528.  
  529.   strcpy(szUniqueName, szSpeaker);
  530.   return 1;
  531. }
  532.  
  533.